[...slug].vue 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. <script setup lang="ts">
  2. import { findPageHeadline } from '#ui-pro/utils/content'
  3. definePageMeta({
  4. layout: 'docs',
  5. })
  6. const route = useRoute()
  7. const { toc } = useAppConfig()
  8. const navigation = inject(navigationInjectionKey)
  9. const { data: page } = await useAsyncData(route.path, () => queryCollection('docs').path(route.path).first())
  10. if (!page.value) {
  11. throw createError({ statusCode: 404, statusMessage: 'Page not found', fatal: true })
  12. }
  13. const { data: surround } = await useAsyncData(`${route.path}-surround`, () => {
  14. return queryCollectionItemSurroundings('docs', route.path, {
  15. fields: ['description'],
  16. })
  17. })
  18. const title = page.value.seo?.title || page.value.title
  19. const description = page.value.seo?.description || page.value.description
  20. useSeoMeta({
  21. title,
  22. ogTitle: title,
  23. description,
  24. ogDescription: description,
  25. twitterTitle: title,
  26. twitterDescription: description,
  27. })
  28. const headline = computed(() => findPageHeadline(navigation?.value, page.value))
  29. const links = computed(() => {
  30. const links = []
  31. if (toc?.bottom?.edit) {
  32. links.push({
  33. icon: 'i-lucide-external-link',
  34. label: 'Edit this page',
  35. to: `${toc.bottom.edit}/${page?.value?.stem}.${page?.value?.extension}`,
  36. target: '_blank',
  37. })
  38. }
  39. return [...links, ...(toc?.bottom?.links || [])].filter(Boolean)
  40. })
  41. </script>
  42. <template>
  43. <UPage v-if="page">
  44. <UPageHeader
  45. :title="page.title"
  46. :description="page.description"
  47. :links="page.links"
  48. :headline="headline"
  49. :ui="{
  50. headline: 'uppercase font-mono font-light text-default-500 text-dim',
  51. }"
  52. />
  53. <UPageBody>
  54. <ContentRenderer
  55. v-if="page"
  56. :value="page"
  57. />
  58. <USeparator v-if="surround?.length" />
  59. <UContentSurround :surround="surround" />
  60. </UPageBody>
  61. <template
  62. v-if="page?.body?.toc?.links?.length"
  63. #right
  64. >
  65. <UContentToc
  66. :title="toc?.title"
  67. :links="page.body?.toc?.links"
  68. >
  69. <template
  70. v-if="toc?.bottom"
  71. #bottom
  72. >
  73. <div
  74. class="hidden lg:block space-y-6"
  75. :class="{ '!mt-6': page.body?.toc?.links?.length }"
  76. >
  77. <USeparator
  78. v-if="page.body?.toc?.links?.length"
  79. type="dashed"
  80. />
  81. <UPageLinks
  82. :title="toc.bottom.title"
  83. :links="links"
  84. />
  85. </div>
  86. </template>
  87. </UContentToc>
  88. </template>
  89. </UPage>
  90. </template>